#include "sdl_canvas.h"

namespace sdl_canvas {

/*
 * class open_frame
 */

open_frame::open_frame(const sdl_ptr<screen> & sc) : sdl_layer(sdl_open_frame_priority, "open_frame"), current_screen(sc)
{
}

open_frame::~open_frame()
{
    _msg("open_frame", 5, "kasowanie open frame " << name());
}

void open_frame::update()
{
    if (!SDL_WasInit(SDL_INIT_VIDEO))
        return;

    // wyczyszczenie ekranu i depth buffera
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // wczytanie macierzy jednostkowej do modelview (zresetowanie transformacji)
    glMatrixMode(GL_MODELVIEW);

    glLoadIdentity();
}

/*
 * class close_frame
 */

close_frame::close_frame(const sdl_ptr<screen> & sc) : sdl_layer(sdl_close_frame_priority, "close_frame"), current_screen(sc)
{
}

close_frame::~close_frame()
{
    _msg("close_frame", 5, "kasowanie close frame " << name());
}

void close_frame::update()
{
    // zamiana bufora ekranu i back buffera (jesteśmy w trybie dwubuforowym)
    if (SDL_WasInit(SDL_INIT_VIDEO))
        SDL_GL_SwapBuffers();
}

/*
 * class screen_info
 */
screen_info::screen_info() : sdl_prim("screen info")
{
    // upewniamy się, że engine jest utworzony
    if (!give<sdl_engine > ())
        _err("screen info", "brak engine");

    xres = yres = 0;

    fullscreen = 0;

    info = NULL;

    screen = NULL;

    // zbieramy informacje o trybie wideo systemu operacyjnego
    info = const_cast<SDL_VideoInfo*> (SDL_GetVideoInfo());
}

screen_info::~screen_info()
{
    _msg("screen info", 5, "kasowanie screen info " << name());
}

const SDL_Surface * screen_info::get_screen()
{
    return screen;
}

const SDL_VideoInfo * screen_info::get_videoinfo()
{
    return info;
}

int screen_info::get_xres()
{
    return xres;
}

int screen_info::get_yres()
{
    return yres;
}

bool screen_info::get_fullscreen()
{
    return fullscreen;
}

/*
 * class screen
 */

screen::screen(int xr, int yr, bool f) :
sdl_layer(sdl_close_frame_priority - 1, "screen"),
of(new open_frame(sdl_ptr<screen>(this))),
cf(new close_frame(sdl_ptr<screen>(this)))
{

    if (!give<sdl_engine > ())
        _err("screen", "brak engine");

    info = give<screen_info > ();

    if (!info)
        _err("screen", "brak instancji screen info");

    info->xres = xr;

    info->yres = yr;

    info->fullscreen = f;

    if (info->info == NULL) {
        std::cerr << "Nie udało się wyciągnąć informacji wideo: " << SDL_GetError() << std::endl;
        throw (sdlex::SDL_exception("Couldn't extract video info"));
    }

    // ustawiamy flagi z którymi włączymy tryb wideo
    int flags = SDL_ANYFORMAT | SDL_OPENGL;

    if (info->fullscreen)
        flags |= SDL_FULLSCREEN;

    // ustawiamy tryb wyświetlania, biorąc głębokość bitową z obecnej aktualnie w systemie
    info->screen = SDL_SetVideoMode(info->xres, info->yres, info->info->vfmt->BitsPerPixel, flags);

    // sprawdzamy, czy wszystko poszło dobrze
    if (info->screen == NULL) {
        std::cerr << "Video mode error: " << SDL_GetError() << std::endl;
        throw (sdlex::SDL_exception("video mode error"));
    }

    // to wymagałoby dłuższych wyjaśnień :)
    SDL_SetClipRect(info->screen, NULL);

    // ustawiamy tytuł okna
    SDL_WM_SetCaption("SDL Demo", NULL);

    // ustawiamy OpenGL
    init_gl();
}

screen::~screen()
{
    _msg("screen", 5, "kasowanie screen " << name());
}

void screen::update()
{
}

void screen::init_gl()
{
    SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5);
    SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 5);
    SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 5);
    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16);
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

    glShadeModel(GL_SMOOTH);
    glEnable(GL_DEPTH_TEST);
    glClearColor(0, 0, 0, 0);
    /*
     * dość zawiła sprawa z ustawianiem perspektywy
     */

    if (give<screen_info > ())
        glViewport(0, 0, give<screen_info > ()->xres, give<screen_info > ()->yres);

    glMatrixMode(GL_PROJECTION);

    glLoadIdentity();

    gluPerspective(60.0, 1.4, 0.1, 1024.0);

    glFrontFace(GL_CCW);
    glCullFace(GL_BACK);
    glEnable(GL_CULL_FACE);
    //glDisable(GL_CULL_FACE);

    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

    //ładowanie rozszerzeń
    sdl_load_gl_extensions();
}

};

template<> sdl_ptr<sdl_canvas::screen_info> sdl_singleton<sdl_canvas::screen_info>::__field = NULL;

